package maurice.game;

import java.io.*;
import java.util.*;

public class HighScore {

	private static final HighScore instance = new HighScore();

	public final static HighScore getInstance() {
		return instance;
	}

	private Integer currentKey;
	private HashMap<Integer, Score> scoreTable;

	private final String PATH_SCORE = "../ressources/high_score.txt";
	private final Integer NB_HIGH_SCORE = 10;

	private HighScore() {
		currentKey = 0;
		scoreTable = new HashMap<Integer, Score>();
		BufferedReader scoreText;
		String line = "";

		File file = new File(PATH_SCORE);
		if (!file.exists()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		try {
			scoreText = new BufferedReader(new FileReader(file));
			do {
				line = scoreText.readLine();
				if (line != null) {
					StringTokenizer st = new StringTokenizer(line);
					while (st.hasMoreTokens()) {
						String login = st.nextToken();
						if (st.hasMoreTokens()) {
							if (st.hasMoreTokens()) {
								Integer score = Integer
										.parseInt(st.nextToken());
								add(login, score);
							}
						}
					}
				}
			} while (line != null);
			scoreText.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void sort() {
		Integer size = scoreTable.size();
		boolean sorted;
		do {
			sorted = false;
			for (Integer i = 0; i < size - 1; i++) {
				if (scoreTable.get(i).getScore() < scoreTable.get(i + 1)
						.getScore()) {
					swap(i, i + 1);
					sorted = true;
				}
			}
			size--;
		} while (sorted);
	}

	private void swap(Integer i, Integer j) {
		Score score1 = scoreTable.get(i);
		Score score2 = scoreTable.get(j);
		scoreTable.remove(i);
		scoreTable.remove(j);
		scoreTable.put(i, score2);
		scoreTable.put(j, score1);
	}

	public void add(String login, Integer score) {
		if (currentKey < NB_HIGH_SCORE)
			scoreTable.put(currentKey++, new Score(login, score));
		else {
			if (score >= getLowestScore()){
				scoreTable.remove(NB_HIGH_SCORE-1);
				scoreTable.put(NB_HIGH_SCORE-1, new Score(login, score));
				sort();
			}
		}
	}
	
	public int getLowestScore(){
		int score = 0;
		
		if (scoreTable.size() > 0){
			score = scoreTable.get(0).getScore();
			for(int key : scoreTable.keySet()){
				int sc = scoreTable.get(key).getScore();
				
				if (sc <= score)
					score = sc;
			}
		}
		
		return score;
	}

	public void clear() {
		scoreTable.clear();
		currentKey = 0;
	}

	public int size() {
		return scoreTable.size();
	}
	
	public boolean isEmpty() {
		return scoreTable.isEmpty();
	}

	public void write() {
		sort();
		try {
			BufferedWriter file = new BufferedWriter(new FileWriter(PATH_SCORE));
			for (Integer i = 0; i < NB_HIGH_SCORE && i < scoreTable.size(); i++) {
				file.write(scoreTable.get(i).write() + "\n");
			}
			file.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public Iterator<Score> iterator() {
		sort();
		return new HighScoreIterator();
	}

	public class HighScoreIterator implements Iterator<Score> {
		Integer index;

		HighScoreIterator() {
			index = 0;
		}

		public boolean hasNext() {
			return index < scoreTable.size() && index < NB_HIGH_SCORE;
		}

		public Score next() {
			return scoreTable.get(index++);
		}

		public void remove() {
			throw new UnsupportedOperationException();
		}
	}

	public class Score {
		private Integer score;
		private String login;

		public Score(String login, Integer score) {
			this.login = login.replace(' ', '_');
			this.score = score;
		}

		public Integer getScore() {
			return score;
		}

		public String toString() {
			return this.score + " points | " + this.login;
		}

		public String write() {
			return this.login + " " + this.score;
		}
	}
}
